﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.HomeServer.Common.Client;
using RouterControl.Whs;
using RouterControl.WhsAddIn.Wizards.EditPortForwarding;

namespace RouterControl.WhsAddIn.ConsoleControls
{
    public partial class PortForwardingEntry : UserControl
    {

        private readonly log4net.ILog _log = Logging.LogFactory.Instance.GetLog<PortForwardingEntry>();
        private PortForwarding _parent;
        private CommonInternetGateway.PortForwarding _forwarding;
        private bool _selected;
        private Color _unselectedBackColor = Color.White;
        private bool _inUpdate = false;
        private int _disableEdittingCountdown = 0;      // countdown for reenabling editting after change; required to sync with updates

        public string ForwardingId
        {
            get;
            private set;
        }

        public Color UnselectedBackcolor
        {
            get
            {
                return _unselectedBackColor;
            }
            set
            {
                _unselectedBackColor = value;

                if (!_selected)
                    this.BackColor = value;
            }
        }

        public bool Selected
        {
            get
            {
                return _selected;
            }

            set
            {
                if (_selected == value)
                    return;

                _selected = value;

                if (value)
                {
                    this.BackColor = Color.Transparent;
                    this.description.BackColor = Color.Transparent;
                    this.BackgroundImage = Properties.Resources.imgPortForwardingEntryBg;

                    // unselect all siblings
                    foreach (var sib in this.Parent.Controls)
                    {
                        var pfe = sib as PortForwardingEntry;

                        if ((pfe != null) && (pfe != this))
                            pfe.Selected = false;
                    }
                }
                else
                {
                    this.BackColor = this.UnselectedBackcolor;
                    this.description.BackColor = Color.White;
                    this.BackgroundImage = null;
                }
            }
        }

        public PortForwardingEntry(PortForwarding parent, CommonInternetGateway.PortForwarding fwd)
        {
            if (parent == null)
	            throw new ArgumentNullException("parent");

            _parent = parent;

            InitializeComponent();

            // clear approval status
            this.statusImage.Image = CommonImages.GrayIcon;

            // setup action images
            this.actionApprove.Image = CommonImages.GreenIcon;
            this.actionDisapprove.Image = CommonImages.RedIcon;

            // register click event on all children
            RegisterOnMouseClick(this.Controls);

            // initialize gui
            UpdateFrom(fwd);
        }

        private void RegisterOnMouseClick(ControlCollection ctls)
        {
            if (ctls == null)
	            throw new ArgumentNullException("ctls");

            foreach (Control c in ctls)
            {
                c.MouseClick += new MouseEventHandler(PortForwardingEntry_MouseClick);
                c.MouseDoubleClick += new MouseEventHandler(PortForwardingEntry_MouseDoubleClick);

                RegisterOnMouseClick(c.Controls);
            }
        }

        public void UpdateFrom(CommonInternetGateway.PortForwarding fwd)
        {
            _inUpdate = true;

            try
            {
	            // update required?
	            if (_forwarding.GetHashCode() != fwd.GetHashCode())
                {
                    // prepare
                    _forwarding = fwd;

                    this.ForwardingId = fwd.Id;

                    UpdateFrom();
                }

                // countdown to reenable editting
                if (_disableEdittingCountdown >= -1)
                {
                    _disableEdittingCountdown--;

                    if (_disableEdittingCountdown == 0)
                    {
                        SetEdittingEnabled(true);
                    }
                }
            }
            finally
            {
                _inUpdate = false;
            }
        }

        private void UpdateFrom()
        {
            // update gui
            this.enabledCB.Checked = _forwarding.Enabled;

            this.externalPortAndProtocol.Text = string.Format(
                "{0} ({1})",
                _forwarding.ExternalPort,
                _forwarding.IsUDP ? "UDP" : "TCP"
                );

            this.remoteHost.Text = (
                string.IsNullOrEmpty(_forwarding.RemoteHost) ?
                "*" :
                _forwarding.RemoteHost
                );

            this.description.Text = _forwarding.PortMappingDescription;

            // try to find client
            {
                var knownClient = (
                    from i in Whs.WhsComputers.Instance.LoadComputers()
                    where i.IP == _forwarding.InternalClient
                    || i.Name == _forwarding.InternalClient
                    select i
                    ).FirstOrDefault();

                var sb = new StringBuilder();

                if (string.IsNullOrEmpty(knownClient.IP))
                {
                    sb.Append(_forwarding.InternalClient);
                }
                else
                {
                    sb.Append(knownClient.Name);
                    sb.Append(" (");
                    sb.Append(knownClient.IP);
                    sb.Append(')');
                }

                sb.Append(':');
                sb.Append(_forwarding.InternalPort);

                this.clientAndinternalPort.Text = sb.ToString();
            }
        }

        private void SetEdittingEnabled(bool enable)
        {
            if (!enable)
            {
                // set countdown
                _disableEdittingCountdown = 2;
            }

            this.actionDelete.Enabled = enable;
            this.actionEditEntry.Enabled = enable;
            this.enabledCB.Enabled = enable;
            this.edittingDisabledImage.Visible = !enable;
        }

        private void PortForwardingEntry_Load(object sender, EventArgs e)
        {
        }

        private void actionMenu_Opened(object sender, EventArgs e)
        {
            this.Selected = true;
        }

        private void actionMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
        }

        private void PortForwardingEntry_MouseClick(object sender, MouseEventArgs e)
        {
            this.Selected = true;
        }

        private void PortForwardingEntry_MouseDoubleClick(object sender, MouseEventArgs e)
        {

        }

        private void actionEditEntry_Click(object sender, EventArgs e)
        {
            RunEditWizard();
        }

        private void actionDelete_Click(object sender, EventArgs e)
        {
            try
            {
                SetEdittingEnabled(false);

                _parent.SingeltonService.Channel.DeletePortForwarding(_forwarding);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to delete port forwarding: " + _forwarding.ToString(), ex);

                Microsoft.HomeServer.Controls.QMessageBox.Show(
                    ex.Message,
                    Properties.Resources.txtPortForwardingDeleteFailedTitle,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                    );
            }
        }

        public void RunEditWizard()
        {
            try
            {
                var wiz = new WizardMain();

                wiz.Forwarding = _forwarding;

                if (wiz.Run() != DialogResult.Cancel)
                {
                    SetEdittingEnabled(false);
                }
            }
            catch (Exception ex)
            {
                _log.Error("Failed to run edit-port-forwarding wizard", ex);
            }
        }

        private void actionApprove_Click(object sender, EventArgs e)
        {
            try
            {
	            _parent.SingeltonService.Channel.SetPortForwardingApproval(
	                _forwarding,
	                true
	                );

                SetApprovalStatus(true);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to approve port forwarding: " + _forwarding.ToString(), ex);

                Microsoft.HomeServer.Controls.QMessageBox.Show(
                    ex.Message,
                    Properties.Resources.txtPortForwardingApprovalFailedTitle,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                    );
            }
        }

        private void actionDisapprove_Click(object sender, EventArgs e)
        {
            try
            {
                _parent.SingeltonService.Channel.SetPortForwardingApproval(
                    _forwarding,
                    false
                    );

                SetApprovalStatus(false);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to disapprove port forwarding: " + _forwarding.ToString(), ex);

                Microsoft.HomeServer.Controls.QMessageBox.Show(
                    ex.Message,
                    Properties.Resources.txtPortForwardingDisapprovalFailedTitle,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                    );
            }
        }

        internal void SetApprovalStatus(bool approved)
        {
            this.statusImage.Image = (
                approved ?
                CommonImages.GreenIcon :
                CommonImages.RedIcon
                );

            this.actionApprove.Visible = !approved;
            this.actionDisapprove.Visible = approved;
        }

        private void enabledCB_CheckedChanged(object sender, EventArgs e)
        {
            if (_inUpdate)
                return;

            try
            {
                SetEdittingEnabled(false);

	            _forwarding.Enabled = this.enabledCB.Checked;
	
	            _parent.SingeltonService.Channel.AddOrUpdatePortForwarding(_forwarding);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to enable/disable port forwarding: " + _forwarding.ToString(), ex);

                Microsoft.HomeServer.Controls.QMessageBox.Show(
                    ex.Message,
                    Properties.Resources.txtPortForwardingEnabledChangeFailedTitle,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                    );
            }
        }

    }
}
